package cn.sylinx.hbatis.ext.starter.springboot;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.springframework.core.env.Environment;

import cn.sylinx.hbatis.ds.DataSourceWrapper;
import cn.sylinx.hbatis.ext.mirage.plugin.SqlResourcePreloadPlugin;
import cn.sylinx.hbatis.ext.starter.pool.DataSourceWrapperFactory;
import cn.sylinx.hbatis.ext.xmapper.plugin.XmapperPlugin;
import cn.sylinx.hbatis.kit.StrKit;
import cn.sylinx.hbatis.log.GLog;
import cn.sylinx.hbatis.plugin.IPlugin;
import cn.sylinx.hbatis.plugin.PluginStarter;
import cn.sylinx.hbatis.plugin.datasource.DataSourcePlugin;
import cn.sylinx.hbatis.plugin.ehcache.EhcachePlugin;
import cn.sylinx.hbatis.plugin.model.ModelPreloadPlugin;
import cn.sylinx.hbatis.plugin.proxy.ProxyPlugin;
import cn.sylinx.hbatis.plugin.transaction.TransactionIsolationPlugin;

class HbatisInitializationBean {

	// 数据源
	private DataSourceWrapper defaultDataSource;
	private Map<String, DataSourceWrapper> multiDataSources = new HashMap<String, DataSourceWrapper>();
	private List<IPlugin> pluginList = new ArrayList<IPlugin>();

	/**
	 * 创建DataSource
	 *
	 * @param type
	 * @param driverClassName
	 * @param url
	 * @param username
	 * @param password
	 * @return
	 */
	private DataSourceWrapper buildDataSource(Map<String, Object> dsMap, Map<String, Object> extConfig) {
		return DataSourceWrapperFactory.buildDataSource(dsMap, extConfig);
	}

	/**
	 * 加载多数据源配置
	 */
	public PluginStarter init(Environment env) {
		initDefaultDataSource(env);
		initMultiDataSources(env);
		initDataSourcePlugin(env);
		initXmapperPlugin(env);
		initModelPreLoadPlugin(env);
		initEhcachePlugin(env);
		initSqlResourcePreloadPlugin(env);
		initTransactionPlugin(env);
		initProxyPlugin(env);
		return initPluginStarter();
	}

	private PluginStarter initPluginStarter() {
		PluginStarter pluginStarter = new PluginStarter(pluginList);
		pluginStarter.start();
		return pluginStarter;
	}

	// 初始化代理插件
	private void initProxyPlugin(Environment env) {

		// TransactionIsolationPlugin
		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "hbatis.plugin.proxy.");
		String clzList = propertyResolver.getProperty("class");
		if (StrKit.isBlank(clzList)) {
			return;
		}

		ProxyPlugin plugin = new ProxyPlugin();
		String[] clzArray = clzList.split(",");
		for (String clz : clzArray) {
			if (StrKit.isNotBlank(clz)) {
				IPlugin item = null;
				try {
					item = (IPlugin) Class.forName(clz.trim()).newInstance();
				} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
					GLog.error("初始化插件失败, clz: " + clz, e);
				}
				if (item != null) {
					// 加入代理插件
					plugin.addPlugin(item);
				}
			}
		}

		pluginList.add(plugin);
	}

	/**
	 * 初始化数据源plugin
	 * 
	 * @param env
	 */
	private void initDataSourcePlugin(Environment env) {

		// 添加默认数据源
		DataSourcePlugin p = new DataSourcePlugin();
		p.setDataSourceWrapper(defaultDataSource);
		pluginList.add(p);

		Set<Entry<String, DataSourceWrapper>> kvSets = multiDataSources.entrySet();
		for (Entry<String, DataSourceWrapper> kv : kvSets) {

			DataSourcePlugin ptmp = new DataSourcePlugin();
			ptmp.setJdbcResourceName(kv.getKey());
			ptmp.setDataSourceWrapper(kv.getValue());
			pluginList.add(ptmp);
		}
	}

	/**
	 * 初始化xmapper插件
	 * 
	 * @param env
	 */
	private void initXmapperPlugin(Environment env) {

		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "hbatis.plugin.xmapper.");
		String inited = propertyResolver.getProperty("inited");
		if (!"true".equalsIgnoreCase(inited)) {
			return;
		}
		GLog.debug("XmapperPlugin inited.");
		// 初始化
		String resourcePath = propertyResolver.getProperty("resourcePath");
		if (resourcePath == null || "".equals(resourcePath)) {
			resourcePath = "xmapper";
		}
		GLog.debug("XmapperPlugin resourcePath:{}", resourcePath);

		XmapperPlugin xmapperPlugin = new XmapperPlugin(resourcePath);
		pluginList.add(xmapperPlugin);
	}

	/**
	 * 初始化modelpreload插件
	 * 
	 * @param env
	 */
	private void initModelPreLoadPlugin(Environment env) {
		// scanPackageList

		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "hbatis.plugin.modelpreload.");
		String inited = propertyResolver.getProperty("inited");
		if (!"true".equalsIgnoreCase(inited)) {
			return;
		}

		GLog.debug("ModelPreloadPlugin inited.");
		ModelPreloadPlugin mp = new ModelPreloadPlugin();

		String acmStrategy = propertyResolver.getProperty("acmStrategy");
		if (StrKit.isNotBlank(acmStrategy)) {
			// 设置全局模型字段映射策略
			mp.setAcmStrategyClass(acmStrategy);
		}

		String scanPackageList = propertyResolver.getProperty("scanPackageList");
		if (StrKit.isNotBlank(scanPackageList)) {
			GLog.debug("ModelPreloadPlugin scanPackageList:{}", scanPackageList);
			String[] pkgArray = scanPackageList.split(",");
			mp.setScanPackageList(Arrays.asList(pkgArray));
		}

		pluginList.add(mp);
	}

	/**
	 * 初始化ehcache插件
	 * 
	 * @param env
	 */
	private void initEhcachePlugin(Environment env) {
		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "hbatis.plugin.ehcache.");
		String inited = propertyResolver.getProperty("inited");
		if (!"true".equalsIgnoreCase(inited)) {
			return;
		}
		GLog.debug("EhcachePlugin inited.");
		pluginList.add(new EhcachePlugin());
	}

	private void initSqlResourcePreloadPlugin(Environment env) {

		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "hbatis.plugin.mirage.");
		String path = propertyResolver.getProperty("sqlpath");
		if (StrKit.isBlank(path)) {
			return;
		}

		GLog.debug("SqlResourcePreloadPlugin inited.");
		String[] pathArray = path.split(",");
		List<String> pathList = Arrays.asList(pathArray);
		SqlResourcePreloadPlugin plugin = new SqlResourcePreloadPlugin(pathList);
		pluginList.add(plugin);
	}

	private void initTransactionPlugin(Environment env) {
		// TransactionIsolationPlugin
		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "hbatis.plugin.transaction.");
		String level = propertyResolver.getProperty("level");
		if (StrKit.isBlank(level)) {
			return;
		}

		GLog.debug("TransactionIsolationPlugin inited.");
		int levelInt = Integer.parseInt(level);
		TransactionIsolationPlugin plugin = new TransactionIsolationPlugin(levelInt);
		pluginList.add(plugin);
	}

	/**
	 * 初始化主数据源
	 */
	private void initDefaultDataSource(Environment env) {

		// 读取主数据源
		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "hbatis.datasource.default.");
		Map<String, Object> dsMap = new HashMap<String, Object>();

		dsMap.put("url", propertyResolver.getProperty("url"));
		dsMap.put("driver", propertyResolver.getProperty("driver"));
		dsMap.put("username", propertyResolver.getProperty("username"));
		dsMap.put("password", propertyResolver.getProperty("password"));
		dsMap.put("dbtype", propertyResolver.getProperty("dbtype"));

		// 获取其它配置
		Map<String, Object> extConfig = propertyResolver.getSubProperties("config.");

		defaultDataSource = buildDataSource(dsMap, extConfig);
	}

	/**
	 * 初始化更多数据源
	 */
	private void initMultiDataSources(Environment env) {
		// 读取配置文件获取更多数据源，也可以通过defaultDataSource读取数据库获取更多数据源
		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "hbatis.datasource.multi.");
		String dsPrefixs = propertyResolver.getProperty("names");
		if (dsPrefixs == null || "".equals(dsPrefixs)) {
			return;
		}

		for (String dsPrefix : dsPrefixs.split(",")) {// 多个数据源
			Map<String, Object> dsMap = propertyResolver.getSubProperties(dsPrefix + ".");
			Map<String, Object> extConfig = propertyResolver.getSubProperties(dsPrefix + ".config.");
			DataSourceWrapper ds = buildDataSource(dsMap, extConfig);
			multiDataSources.put(dsPrefix, ds);
		}
	}

}
